package com.base.monitor.module.biz.server;

import cn.hutool.core.util.StrUtil;
import com.base.monitor.model.constant.CollectConstant;
import com.base.monitor.model.model.biz.cfg.entity.Gateway;
import com.base.monitor.module.biz.context.CfgContext;
import com.base.monitor.module.biz.context.ClientContext;
import com.base.monitor.module.biz.properties.NetworkProperties;
import com.base.monitor.module.biz.service.collect.HandlerMessageService;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.stereotype.Component;

@Slf4j
@Component
@ChannelHandler.Sharable
@EnableConfigurationProperties(NetworkProperties.class)
public class ReceiveDataHandler extends SimpleChannelInboundHandler<String> {

//    private static final Map<String, Integer> idleMap = new ConcurrentHashMap<>();

    @Autowired
    private HandlerMessageService handlerMessageService;

    @Autowired
    private NetworkProperties networkProperties;

    /**
     * 接收客户端发过来的数据
     * @param ctx 信道上下文信息
     * @param msg 数据
     * @throws Exception
     */
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
        String ip = ctx.channel().remoteAddress().toString();
        if (networkProperties.getBeatInfo().equals(msg)) {
            log.info("收到来自{}客户端的心跳包", ip);
            // 更新网关的在线时间
            updateGatewayOnlineTime(ctx);
        } else {
            // 获取消息的类型。现阶段的类型可能为连接、指标和命令
            String messageType = this.getMessageType(msg);
            // 处理消息
            handlerMessageService.handle(messageType, ctx, msg);
        }
    }

    /**
     * 更新网关的在线时间
     * @param ctx 信道上下文信息
     */
    private void updateGatewayOnlineTime(ChannelHandlerContext ctx) {
        // 1.获取对应的信道信息
        ClientContext.ChannelInfo channelInfo = ClientContext.getChannelInfoById(ctx.channel().id().asShortText());
        if (channelInfo == null) {
            return;
        }

        // 2.获取信道信息的连接命令command
        String command = channelInfo.getCommand();
        if (StrUtil.isBlank(command)) {
            return;
        }

        // 3.过滤gatewayList，选出里面command的值等于上面获取到的command值的记录
        Gateway gateway = CfgContext.getGatewayVoByCommand(command);

        // 4.更新在线时间
        if (gateway != null) {
            CfgContext.addGatewayOnlineTime(gateway.getGatewayId());
        }

    }

    /**
     * 根据消息的内容获取消息的类型
     * TODO 添加消息类型时，这里需要跟着新增
     * @param msg 消息的内容
     * @return
     */
    private String getMessageType(String msg) {
        if (msg.startsWith(networkProperties.getConnectMessagePrefix())) {
            return CollectConstant.MESSAGE_TYPE_IS_CONNECT;
        }
        if (msg.startsWith(networkProperties.getIndicatorMessagePrefix())) {
            return CollectConstant.MESSAGE_TYPE_IS_INDICATOR;
//            return CollectConstant.MESSAGE_TYPE_IS_BRIGHT_SKY_FIRE_CONTROL_RESET;
        }
        if (msg.startsWith(networkProperties.getVersionMessagePrefix())) {
            return CollectConstant.MESSAGE_TYPE_IS_VERSION;
        }
        if (msg.startsWith(networkProperties.getBrightSkyFireControlIndicatorMessagePrefix())) {
            return CollectConstant.MESSAGE_TYPE_IS_BRIGHT_SKY_FIRE_CONTROL_INDICATOR;
        }
        if (msg.startsWith(networkProperties.getBrightSkyFireControlResetMessagePrefixSuffix())
                && msg.endsWith(networkProperties.getBrightSkyFireControlResetMessagePrefixSuffix())) {
            return CollectConstant.MESSAGE_TYPE_IS_BRIGHT_SKY_FIRE_CONTROL_RESET;
        }
        if (msg.startsWith(networkProperties.getTandaFireControlMessagePrefix())) {
            return CollectConstant.MESSAGE_TYPE_IS_TANDA_FIRE_CONTROL;
        }
        return CollectConstant.MESSAGE_TYPE_IS_COLLECT;
    }

//    /**
//     * 当没有再规定的时间内收到心跳包会执行的逻辑
//     * 进行超时处理
//     * @param ctx 客户端channel的上下文
//     * @param evt 事件对象
//     * @throws Exception
//     */
//    @Override
//    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
//        Channel channel = ctx.channel();
//        String ip = channel.remoteAddress().toString();
//        IdleStateEvent event = (IdleStateEvent) evt;
//
//        // 非读空闲不进行操作
//        if (!event.state().equals(IdleState.READER_IDLE)) {
//            return;
//        }
//
//        // 计算每次超时后，一共超时了多少次
//        Integer idleCount = idleMap.get(ip);
//        if (idleCount == null) {
//            idleCount = 1;
//        } else {
//            idleCount++;
//        }
//        log.info("客户端{}出现读空闲，总计读空闲次数为{}", ip, idleCount);
//        if (idleCount == 3) {
//            log.info("客户端{}出现的读空闲次数超过3次，关闭连接，释放更多资源", ip);
//            if (ctx.channel().isActive()) {
//                ctx.channel().close();
//            }
//            idleMap.remove(ip);
//            ClientContext.removeClient(ctx);
//            return;
//        }
//
//        idleMap.put(ip, idleCount);
//    }

//    @Override
//    public void channelActive(ChannelHandlerContext ctx) throws Exception {
//        log.warn("=== " + ctx.channel().remoteAddress().toString() + " is active ===");
//    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        log.error("=== " + ctx.channel().remoteAddress() + " error, cause: {} ===", cause.getMessage(), cause);
    }
}